home *** CD-ROM | disk | FTP | other *** search
- /*
- TMS9900/99105 Cross-Assembler v. 1.0
-
- January, 1985
-
- Original 6800 version Copyright (c) 1980 William C. Colley, III.
- Modified for the TMS9900/99105 Series by Alexander Cameron.
-
- File: a99asmln.c
-
- Line assembly routine.
- */
-
- /* Get globals: */
-
- #include "a99.gbl"
-
- /*
- This function is the workhorse of the assembler. The routine
- gets any labels off the line and processes them, gets the opcode
- and builds the binary output as it evaluates the operand field.
- */
-
- asmline()
- {
- char c,label[2*SYMLEN], opattr;
- unsigned opcode,op2;
- nbytes = 0;
- address = pc;
- directok = TRUE;
- evalerr = FALSE;
- hexflg = NOCODE;
- label[0] = '\0';
- binbuf[0] = binbuf[2] = binbuf[4] = 0x10;
- binbuf[1] = binbuf[3] = binbuf[5] = 0; /* NOP = 0x1000 */
- switch (getchr(&c,NOSKIP))
- {
- case ALPHA: backchr;
- getname(label);
- if (chkoprat(label) != NO_OPR)
- {
- markerr('L');
- label[0] = '\0';
- }
- break;
-
- case END_LIN: return;
-
- case BLANK: break;
-
- default: markerr('L');
- while((c = getchr(&c,NOSKIP)) != BLANK && c != END_LIN);
- backchr;
- }
- switch(getopcod(&opcode,&opattr))
- {
- case 0: nbytes = 0;
-
- case -1: opcode = 255; /* Set nil pseudo-op. */
- opattr = 0x80;
-
- case 1: if ((opattr & (PSOP | IFGROUP)) == (PSOP | IFGROUP))
- {
- if (label[0] != '\0') markerr('L');
- }
- else
- {
- if (ifstack[ifsp] == 0) return;
- if (label[0] != '\0')
- {
- strcat(label,PADDING);
- if (pass == 1)
- {
- if (addsym(label))
- {
- sympoint -> symvalu = pc;
- if ((opattr & PSOP) && opcode==0x000A)
- {
- sympoint -> symname[1] |= 0x80;
- }
- }
- }
- else
- {
- if (slookup(label))
- {
- markerr('P');
- label[0] = '\0';
- }
- else
- {
- if (sympoint -> symvalu != pc || (sympoint -> symname[1] & 0x80))
- {
- markerr('M');
- }
- sympoint -> symname[0] &= 0x7f;
- }
- }
- }
- }
- hexflg = PUTCODE;
- if (opattr & PSOP) _psop(opcode,label);
- else _normop(opcode,opattr);
- return;
- }
- }
-
- /*
- Internal function to process pseudo opcodes.
- */
-
- _psop(opcode,label)
- char *label;
- unsigned opcode;
- {
- char *bptr, c, d;
- unsigned t,temp;
- struct symbtbl *sptr;
- sptr = sympoint;
- bptr = binbuf;
- switch (opcode)
- {
- case 0: t = eval(START); /* ORG. */
- if (evalerr) return;
- address = pc = t;
- hexflg = FLUSH;
- if (label[0] == '\0') goto chkargs;
- backitem(t,VALUE);
- backchr;
-
- case 1: if (label[0] == '\0') /* EQU. */
- {
- markerr('L');
- return;
- }
- if (!(sptr -> symname[1] & 0x80) && errcode == 'M')
- {
- errcode = ' ';
- errcount--;
- }
- t = eval(START);
- if (evalerr) return;
- address = sptr -> symvalu;
- sptr -> symvalu = t;
- if (!directok) markerr('P');
- if (address != t) markerr('M');
- goto chkargs;
-
- case 2: /* BYTE */
- while ((c = getitem(&t,SMALST)) != END_LIN)
- {
- if (c == COMMA)
- {
- *bptr++ = 0;
- nbytes++;
- continue;
- }
- backitem(t,c);
- t = eval(START);
-
- /* mod because eval now returns delimeter- gobbles up comma */
- c=getitem(&temp,SMALST);
- if (evalerr || t > 0xff && t < 0xff80) markerr('V');
- *bptr++ = t;
- nbytes++;
- if(c==END_LIN) return;
- }
- return;
-
- case 3: /* WORD */
- while ((c = getitem(&t,SMALST)) != END_LIN)
- {
- if (c == COMMA)
- {
- *bptr++ = 0;
- *bptr++ = 0;
- nbytes += 2;
- continue;
- }
- backitem(t,c);
- t=eval(START);
- c=getitem(&temp,SMALST);
- *bptr++ = t >> 8;
- *bptr++ = t;
- nbytes += 2;
- if(c==END_LIN) return;
- }
- return;
-
- case 4: /* TEXT */
- while ((c = getchr(&d,SKIP)) != END_LIN)
- {
- if (c == COMMA) continue;
- if (c != QUOTE)
- {
- markerr('"');
- /*return;*/
- }
- while ((c = *linptr++) != d)
- {
- if (c == '\n')
- {
- markerr('"');
- return;
- }
- *bptr++ = c;
- nbytes++;
- }
- }
- return;
-
- case 5: t = eval(START); /* BSS */
- /* if (evalerr) return; */
- pc += t;
- hexflg = FLUSH;
- goto chkargs;
-
- case 6: if (pass == 1) pass--; /* END. */
- else
- {
- pass++;
- if (ifsp != 0) markerr('I');
- }
- hexflg = NOMORE;
- goto chkargs;
-
- case 7: /* ELSE. */
- case 8: hexflg = NOCODE; /* ENDI. */
- if (ifsp == 0)
- {
- markerr('I');
- return;
- }
- if (opcode == 8) ifsp--;
- else ifstack[ifsp] = ~ifstack[ifsp];
- goto chkargs;
-
- case 9: t = eval(START); /* IF. */
- if (evalerr || !directok)
- {
- markerr('P');
- t = 0xffff;
- }
- if (ifsp == 16) wipeout("\nIf stack overflow.\n");
- ifstack[++ifsp] = address = t;
- goto chkargs;
-
- case 10: if (label[0] == '\0') /* SET. */
- {
- markerr('L');
- return;
- }
- if ((sptr -> symname[1] & 0x80) && errcode == 'M')
- {
- errcode = ' ';
- errcount--;
- }
- t = eval(START);
- if (evalerr) return;
- address = sptr -> symvalu = t;
- if (!directok) markerr('P');
- goto chkargs;
-
- case 11: if(pc & 1) /* EVEN */
- { nbytes++;
- *bptr=0;
- }
- goto chkargs;
-
- case 12: hexflg=NOCODE; /* DXOP */
- if(getchr(&c,SKIP) != ALPHA)
- {
- markerr('S');
- return;
- }
- backchr;
- getname(label); /* name of DXOP */
- strcat(label,PADDING);
- getitem(&t,SMALST); /* skip to number */
- t=eval(START); /* DXOP number */
- if(evalerr || t >15)
- {
- markerr('S');
- return;
- }
- if( pass == 1)
- if(addsym(label)) sympoint ->symvalu = ( 0x2C00 | t << 6 ); /* XOP opcode */
-
- return;
-
- chkargs: if (getitem(&c,SMALST) != END_LIN) markerr('T');
- return;
-
- case 255: /* NO OPCODE. */
- if (nbytes == 0) hexflg = NOCODE;
- return;
- }
- }
-
- /*
- Internal function to process normal (non-pseudo) opcodes.
- */
-
- _normop(opcode,attr)
- unsigned opcode;
- char attr;
- {
- unsigned regmask,regval,t,operand,value;
- int disp;
- char shift,c,parse,opdcount,attr1,attr2;
- nbytes = 2;
- if(pc & 1){ pc++; address++; } /* make sure code is on an even boundary */
- operand=0;
- attr1=attr & 0x07; /* mask 3 most least significant bits */
- attr2=(attr & 0x38) >> 3; /* next 3 bits represent attr2 */
- attr=attr1;
- opdcount=1;
- while(TRUE)
- { parse=TRUE;
- addrmode=WREG; /* default address mode */
- switch(attr)
- {
-
- case 0: if(attr1 || attr2) markerr('S');
- binbuf[0] = opcode >> 8;
- binbuf[1] = opcode;
- if(c=getitem(&value,SMALST) != END_LIN) markerr('T');
- return;
-
- /* Format 1 - S,D */
- /* detect N,*N,*N+,@X,@X(N) */
-
- case 1: while(parse)
- {
- switch(c=getitem(&value,SMALST))
- {
-
- case OPERATR: if(value=='*')addrmode=INDIRECT;
- if(value=='@')
- {
- addrmode=SYMBOLIC;
- nbytes += 2;
-
- }
- break;
-
- case VALUE : regval = 0;
- backitem(value,c);
- t=eval(START);
- if(evalerr) markerr('S');
- switch(addrmode)
- {
- case WREG: regval=t;regmask=0;break;
- case INDIRECT: regval=t;regmask=1;break;
- case AUTOINC: regval=t;regmask=3;break;
- case SYMBOLIC: regmask=2;
- binbuf[nbytes - 2] = t>>8;
- binbuf[nbytes - 1] = t;
- break;
- case INDEXED: regmask=2;
- binbuf[nbytes - 2] = t >> 8;
- binbuf[nbytes - 1] = t;
- regval=eval(START);
- if(evalerr) markerr('E');
- }
- if(regval > 15) markerr('R');
-
- if(opdcount == 2) shift=6;
- else shift=0;
- operand |= (regval << shift);
- operand |= (regmask << shift + 4);
- break;
-
- case COMMA: opdcount++;
- if(opdcount > 3) {markerr('T'); break;}
- attr=attr2;
- parse=FALSE;
- break;
-
- case END_LIN: opcode |= operand;
- binbuf[0]=opcode>>8;
- binbuf[1]=opcode;
- return;
- }
- }
- break;
-
- /* case 2 handles signed displacement */
-
- case 2: while(TRUE)
- { switch(c=getitem(&value,SMALST))
- {
- case OPERATR:
- case VALUE: backitem(value,c);
- operand=eval(START);
- break;
-
- case END_LIN: operand -=pc+2;
- disp=operand/2;
- if(disp > 127 && disp > -128) markerr('B');
- opcode |= disp & 0xff;
- binbuf[0]=opcode>>8;
- binbuf[1]=opcode;
- return;
-
- default: markerr('S');
- }
- }
-
- /* Destination register only - D and also C */
-
- case 3: regval = eval(START);
- if( evalerr) markerr('S');
- if( regval > 15 ) markerr('R');
- if( getitem(&value,SMALST) != END_LIN) markerr('T');
- if(opdcount != 2) markerr('S');
- operand |= regval << 6;
- opcode |= operand;
- binbuf[0]=opcode>>8;
- binbuf[1]=opcode;
- return;
-
-
- /* Bit field operands */
-
- case 4: disp=eval(START);
- if(evalerr) markerr('S');
- opcode |= disp & 0xff;
- binbuf[0] = opcode >> 8;
- binbuf[1] = opcode;
- if(getitem(&value,SMALST) != END_LIN) markerr('T');
- return;
-
- /* Workspace register - W or shift count C */
-
- case 5: while(parse)
- {
- switch(c=getitem(&value,SMALST))
- {
- case VALUE:
- case OPERATR: backitem(value,c);
- regval=eval(START);
- if(regval > 15 ) markerr('R');
- if(opdcount == 2) operand |= regval << 4;
- else operand = regval;
- break;
-
- case COMMA: opdcount++;
- if(opdcount > 3) {markerr('T'); break;}
- parse = FALSE;
- attr=attr2;
- break;
-
-
- case END_LIN: opcode |= operand;
- binbuf[0] = opcode >> 8;
- binbuf[1] = opcode;
- return;
-
- }
- }
- break;
-
- /* Immediate operation - IOP */
-
- case 6: nbytes += 2;
- t = eval(START);
- opcode |= operand;
- binbuf[0] = opcode >> 8;
- binbuf[1] = opcode;
- binbuf[2] = t >> 8;
- binbuf[3] = t;
- if(getitem(&value,SMALST) != END_LIN) markerr('T');
- return;
-
- /* Bit Manipulation Instructions - for the 99105 only
- this instruction has a very similar format to the CRU
- Bit Manipulation set and but the opcode addressing modes
- are in the second word i.e. [ opcode ]
- [ format3|format1]
- hence calling _normop recursively we can then easily
- swap the words around to produce the correct code */
-
- case 7: _normop(0x0000,0x19); /* call with opcode 0 and format 3 and format 1 */
- nbytes += 2; /* binbuf[0,1,2,3] now hold the 2nd and 3rd word */
- binbuf[4] = binbuf[2]; /* shift data down by 1 word to */
- binbuf[5] = binbuf[3]; /* allow for opcode */
- binbuf[2] = binbuf[0];
- binbuf[3] = binbuf[1];
- binbuf[0] = opcode >> 8; /* now place original opcode in 1st word */
- binbuf[1] = opcode;
- return;
-
- default: wipeout("bad operand format -- aborting \n");
- exit();
- }
- }
- }